local jass           = require 'jass.common'
local japi           = require 'jass.japi'
local slk            = require 'jass.slk'
local dbg            = require 'jass.debug'
local hook           = require 'jass.hook'
local code           = require 'jass.code'

local symbols        = require 'symbol.unit'
local handlelib      = require 'util.handle'
local colorlib       = require 'util.color'
local japi2          = require 'util.japi2'

local math_floor     = math.floor 

local handle_manager = handle_manager_class:create()

---@class unit "单位"
local unit           = {}
setmetatable(unit, unit)
ac.unit = unit

--- 存放所有单位
unit.allunits = {}
--- 存放移除的单位handle
unit.removeds = {}
--- 存放预设单位
unit.globals = {}
--- 恢复帧率
unit.regenframe = 0.25
--- 恢复组
unit.regengroup = { }

--- 护甲类型表
unit.AmorTypes = {
    [0] = '小型',
    ['小型'] = 0,
    [1] = '中型',
    ['中型'] = 1,
    [2] = '大型',
    ['大型'] = 2,
    [3] = '城墙',
    ['城墙'] = 3,
    [4] = '普通',
    ['普通'] = 4,
    [5] = '英雄',
    ['英雄'] = 5,
    [6] = '神圣',
    ['神圣'] = 6,
    [7] = '无装甲',
    ['无装甲'] = 7,
}
--- 攻击类型表
unit.AttackTypes = {
    [0] = '法术',
    ['法术'] = 0,
    [1] = '普通',
    ['普通'] = 1,
    [2] = '穿刺',
    ['穿刺'] = 2,
    [3] = '攻城',
    ['攻城'] = 3,
    [4] = '魔法',
    ['魔法'] = 4,
    [5] = '混乱',
    ['混乱'] = 5,
    [6] = '英雄',
    ['英雄'] = 6,
}

unit.allow_flag = {
    ["地面"]	= 2 ^ 1,
    ["空中"]	= 2 ^ 2,
    ["建筑"]	= 2 ^ 3,
    ["守卫"]	= 2 ^ 4,
    ["物品"]	= 2 ^ 5,
    ["树木"]	= 2 ^ 6,
    ["墙"]		= 2 ^ 7,
    ["残骸"]	= 2 ^ 8,
    ["装饰物"]	= 2 ^ 9,
    ["桥"]		= 2 ^ 10,
    --["未知"]	= 2 ^ 11,
    ["自己"]	= 2 ^ 12,
    ["玩家单位"]	= 2 ^ 13,
    ["联盟"]	= 2 ^ 14,
    ["中立"]	= 2 ^ 15,
    ["敌人"]	= 2 ^ 16,
    --["未知"]	= 2 ^ 17,
    --["未知"]	= 2 ^ 18,
    --["未知"]	= 2 ^ 19,
    ["可攻击的"]	= 2 ^ 20,
    ["无敌"]	= 2 ^ 21,
    ["英雄"]	= 2 ^ 22,
    ["非-英雄"]	= 2 ^ 23,
    ["存活"]	= 2 ^ 24,
    ["死亡"]	= 2 ^ 25,
    ["有机生物"]	= 2 ^ 26,
    ["机械类"]	= 2 ^ 27,

    ["无抗性外壳"]	= 2 ^ 30,
    ["有抗性外壳"]	= 2 ^ 31,

    ["非-自爆工兵"]	= 2 ^ 28,
    ["自爆工兵"]	= 2 ^ 29,

    -- ["非-古树"]	= 2 ^ 30,
    -- ["古树"]	= 2 ^ 31,
}

unit.dbgcount = 0

local mt = {}
unit.__index = mt
-- 单位继承物体类
setmetatable(mt, ac.widget)

--- 类型
mt.type = 'unit'

--- 句柄
mt.handle = jass.ConvertUnitState(0)

--颜色
mt.red = 255
mt.green = 255
mt.blue = 255
mt.alpha = 255

--- 获取ID
function mt:get_id()
    return self._name
end

--- 获取所有者
--- @return player
function mt:get_owner()
    return self.owner
    -- if self.removed then
    --     return self.owner
    -- end
    -- return ac.player(jass.GetOwningPlayer(self.handle))
end

--- 改变所有者
function mt:set_owner(player)
    if not self.removed then
        local skills = {}
        for skill in self:each_skill() do
            if skill.upgrades or skill.requires then
                skill:notify("on_remove")
                skills[#skills + 1] = skill
            end
        end
        jass.SetUnitOwner(self.handle, player.handle, true)
        self.owner = player
        self:notify("单位-改变所有者", self, player)
        for i = #skills, 1, -1 do
            skills[i]:notify("on_add")
        end
    end
end

--- 获取位置
function mt:get_point()
    if self.removed then
        return self._last_point
    end
    return ac.widget.get_point(self)
end

--- 获取锚点坐标
function mt:get_anchor_point()
    local x, y = jass.GetUnitX(self.handle), jass.GetUnitY(self.handle)
    if self:is_build() then
        return x, y
    end
    local collision = self:get_collision()
    if collision >= 48 or (collision < 32 and collision >= 16) then
        x = x - 16
        y = y - 16
    end
    return x, y
end

-- 是否在指定位置附近(计算碰撞)
function mt:is_in_range(p, radius)
	if p.type == 'unit' then
		return self:get_point() * p:get_point() - (self:get_collision() + p:get_collision()) <= radius
	end

	return self:get_point() * p:get_point() - self:get_collision() <= radius
end

--播放动画
function mt:play_animation(name)
    if type(name) == 'string' then
        local session = ac.lni('unit', self:get_id())
        if session and session.animations then
            name = session.animations[name] or name
        end
        jass.SetUnitAnimation(self.handle,self.animation_properties ..  name)
    else
        jass.SetUnitAnimationByIndex(self.handle, name)
    end
end
function mt:set_animation(name)
    self:play_animation(name)
end

--设置动画播放速度
function mt:set_animation_speed(speed)
    jass.SetUnitTimeScale(self.handle, speed)
end

--添加动画
function mt:add_animation(ani,force)
	if force ~= true then
		if not self:is_alive() then
			return
		end
	end
	jass.QueueUnitAnimation(self.handle, ani)
end

mt.animation_properties = ''
function mt:add_animation_properties(name)
    jass.AddUnitAnimationProperties(self.handle, name, true)
	self.animation_properties = self.animation_properties .. name .. ' '
end

--移除动画
function mt:remove_animation_properties(name)
    jass.AddUnitAnimationProperties(self.handle, name, false)
	self.animation_properties = self.animation_properties:gsub(name .. ' ', '')
end

local function play_force_animation(hero)
    local list = hero.force_animation_list
    local data = list[1]
    hero:play_animation(data[1])
    ac.wait(data[2]*1000,function()
        table.remove(hero.force_animation_list,1)
        if #hero.force_animation_list==0 then
            hero:remove_restriction '硬直'
        else
            play_force_animation(hero)
        end
    end)
end

function mt:force_animation(name,time)
    if self.force_animation_list==nil then
        self.force_animation_list = {}
    end
    table.insert(self.force_animation_list,{name,time})
    if #self.force_animation_list==1 then
        self:add_restriction '硬直'
        ac.wait(0,function()
            play_force_animation(self)
        end)
    end

end

--是某个类别
function mt:is_type(name)
	if not self.types then
        return false
	end
    if self.types[name] then
        return true
    else
        return false
    end
end


function mt:set_type(data)
	local types = {}
    if type(data) == 'string' then
        data = data:split(',')
		for _, tp in ipairs(data) do
			types[tp] = true
        end
    elseif type(data) == 'table' then
		for _, tp in ipairs(data) do
			types[tp] = true
        end
    end
    self.types = types
end

function mt:add_type(name)
	self.types[name] = true
end

function mt:remove_type(name)
	self.types[name] = nil
end

--是否是敌人
function mt:is_enemy(dest)
    return self:get_owner():is_enemy(dest:get_owner())
end

--是否是友军
function mt:is_ally(dest)
    return self:get_owner():is_ally(dest:get_owner())
end

--是否是中立
function mt:is_neutral(dest)
    return dest:get_owner():is_neutral()
end

--是否是盟友
function mt:is_league(dest)
    return self:get_owner():is_league(dest:get_owner())
end

--获取名字
function mt:get_name()
    if not self.name then
        self.name = jass.GetUnitName(self.handle)
    end
    return self.name
end

--设置名字
function mt:set_name(name)
    self.name = name
    japi.SetUnitName(self.handle, name)
    if self:is_hero() then
        japi.SetUnitProperName(self.handle, name)
    end
end

-- 获取称谓
function mt:get_proper_name(name)
    if not self.proper_name then
        return self.name
    end
    return self.proper_name
end

--设置称谓
function mt:set_proper_name(name)
    self.proper_name = name
    if self:is_hero() then
        japi.SetUnitProperName(self.handle, name)
    end
end

--- 设置单位坐标
--- @params point 点
--- @params is_stop 是否发布停止命令
function mt:set_point(point, is_stop)
    local x, y = point:get()
    if is_stop == true then
        jass.SetUnitPosition(self.handle, x, y)
    else
        jass.SetUnitX(self.handle, x)
        jass.SetUnitY(self.handle, y)
    end
    self:notify('单位-改变位置', self, point)
end

-- 移动单位到指定位置(检查碰撞)
--	移动目标
--	[无视地形阻挡]
--	[无视地图边界]
function mt:set_position(where, path, super)
	if self:has_restriction '禁锢' then
		return false
	end
	if where:get_point():is_block(path, super) then
		return false
	end
	local x, y = where:get_point():get()
	local x1, y1, x2, y2 = ac.rect.map:get()
	if x < x1 then
		x = x1
	elseif x > x2 then
		x = x2
	end
	if y < y1 then
		y = y1
	elseif y > y2 then
		y = y2
	end
	self:set_point(ac.point(x, y))
	return true
end

--- 获取朝向
function mt:get_facing()
    return jass.GetUnitFacing(self.handle)
end

--- 设置朝向
--- @params alg 角度
--- @params is_instant 瞬间转向
function mt:set_facing(angle, is_instant)
    if is_instant == true then
        japi.EXSetUnitFacing(self.handle, angle)
    else
        jass.SetUnitFacing(self.handle, angle)
    end
end

-- 获取碰撞半径
function mt:get_collision()
    return self:get_slk('collision', 32.0)
end

-- 设置碰撞体积
function mt:set_collision(size)
    japi.SetUnitCollisionSize(self.handle, size)
end

-- 关闭碰撞
function mt:set_collision_enable(flag)
    -- japi.EXSetUnitCollisionType(flag,self.handle,1)
    jass.SetUnitPathing(self.handle, flag)
end

--- 获取单位存活状态
function mt:is_alive()
    return japi.UnitAlive(self.handle)
end

--- 获取单位存活状态
function mt:is_dead()
    return japi.UnitAlive(self.handle) == false
end

--- 单位对玩家是否可见
--- @params dest player
function mt:is_visible(player)
    return jass.IsUnitVisible(self.handle, player.handle)
end

--- 是否隐藏
function mt:is_hidden()
    return jass.IsUnitHidden(self.handle)
end

--- 是英雄
function mt:is_hero()
    return jass.IsUnitType(self.handle, 0)
end

--- 是守卫
function mt:is_ward()
    return self:get_slk("type", ""):find("ward")
end

--- 是古树
function mt:is_ancient()
    return jass.IsUnitType(self.handle, 19)
end

--- 是召唤物
function mt:is_summon()
    return self.summon_flag
end

--- 是建筑物
function mt:is_build()
    return jass.IsUnitType(self.handle, 2)
end

--- 是地面单位
function mt:is_ground()
    return (jass.IsUnitType(self.handle, 3) == false)
    -- return jass.IsUnitType(self.handle, 4)
end

--- 是守卫
function mt:is_ward()
    return self.ward_flag
end

--- 是飞行单位
function mt:is_flying()
    return jass.IsUnitType(self.handle, 3)
end

--被装载
function mt:is_loaded()
    return jass.IsUnitLoaded(self.handle)
end

--- 是商店
function mt:is_store()
    return self:has_ability 'Aneu'
end

unit.weapon_types = {
    [4] = "立即",
    [0] = "没有",
    [1] = "近战",
}

--- 是近战单位
function mt:is_combat()
    return (self.weapon_type == 1) or (self.weapon_type == 4) or (self.weapon_type == 0)
end

--- 设置单位显示
function mt:show()
    jass.ShowUnit(self.handle, true)
end

--- 设置单位隐藏
function mt:hide()
    jass.ShowUnit(self.handle, false)
end

--- 获取默认高度
function mt:get_default_height()
    return jass.GetUnitDefaultFlyHeight(self.handle)
end

--- 获取单位高度
function mt:get_height()
    return jass.GetUnitFlyHeight(self.handle)
end

--- 设置高度
function mt:set_height(height, speed)
    jass.SetUnitFlyHeight(self.handle, height or 0, speed or 0)
    self:notify('单位-改变高度', self, height)
end

-- 增加高度
--	高度
--	[是否是绝对高度]
function mt:add_height(height, b)
	self:set_height(self:get_height(b) + height)
end


-- 获取当前命令
function mt:current_order(flag)
    local orderid = jass.GetUnitCurrentOrder(self.handle)
    if not flag then
        return Order[orderid]
    end
    return orderid
end
function mt:get_order(flag)
    return self:current_order()
end

--- 设置自定义值
function mt:set_data(key, value)
    if not self.user_data then
        self.user_data = {}
    end
    self.user_data[key] = value
end

--- 获取自定义值
function mt:get_data(key,default)
    if not self.user_data then
        self.user_data = {}
    end
    return self.user_data[key] or default
end

--设置血条是否隐藏
function mt:set_press_ui_visible(flag)
    japi.SetUnitPressUIVisible(self.handle, flag or false)
end

function mt:set_model(model)
	if self:is_alive() and model then
        self.model = (model):gsub("[mM][dD][lL]", "mdx") or ".mdx"
        japi.SetUnitModel(self.handle, self.model)
        -- japi.SetUnitPortrait(self.handle, (self.model:match("(.+)%..+$") or self.model) .. "_portrait.mdx")
        local modelScale = self:get_slk('modelScale', 1.0)
        self.unit_overhead = ac.message.unit_overhead(self.handle)
        if modelScale ~= 0 then 
            self.unit_overhead = self.unit_overhead / modelScale
        end 
    end
end

--设置镜头模型
function mt:set_protrait(model)
    japi.SetUnitPortrait(self.handle, model or '0.mdx')
end

--获取弹道命中z偏移
function mt:get_impactZ()
    return self:get_slk('impactZ', 0) * self:get_current_scale()
end

--获取弹道命中点
function mt:get_impact_point()
    local point = self:get_point()
    point.z = point:get_height() + self:get_height() + self:get_impactZ()
    return point
end

-- 获取默认转向点
function mt:get_default_propwindow()
    if not self.default_prowindow then
        self.default_prowindow = self:get_propwindow()
    end
    return self.default_prowindow
end

-- 获取转向点
function mt:get_propwindow()
    return jass.GetUnitPropWindow(self.handle)
end

-- 设置转向点
function mt:set_propwindow(value)
    if not self.default_prowindow then
        self.default_prowindow = jass.GetUnitPropWindow(self.handle)
    end
    jass.SetUnitPropWindow(self.handle, value)
end

-- 获取弹道发射x
function mt:get_launch_x()
    return self:get_slk('launchX', 0)
end

-- 获取弹道发射y
function mt:get_launch_y()
    return self:get_slk('launchY', 0)
end

-- 获取弹道发射z
function mt:get_launch_z()
    return self:get_slk('launchZ', 0)
end

--获取弹道发射点
function mt:get_launch_point()
    local x, y = self:get_anchor_point()
    local angle = self:get_facing()
    local scale = self:get_current_scale()
    return ac.point(
        x + math.cos(angle) * (self:get_launch_x() * scale),
        y + math.sin(angle) * (self:get_launch_y() * scale),
        (self:get_launch_z() * scale) + self:get_height() + ac.point.get_location_height(x, y)
    )
end

--获取单位模型
function mt:get_model()
    if not self.model then
        local model = self:get_slk('file', '.mdx')
        local ftype = model:sub(-4):upper()
        if ftype ~= '.MDX' and ftype ~= '.MDL' then
            model = model .. '.mdx'
        end
        self.model = model
    end
    return self.model
end

--按ID设置单位的贴图
function mt:set_texture(normal_image, id)
    if self.removed then return end
    japi.SetUnitTexture(self.handle, normal_image or "", id or 32)
end

--设置缩放
function mt:set_size(scale)
    self.scale = scale
    local percentage = math.max(self:get("单位体型"), 0.01) * 0.01
    local current_scale = self.scale * percentage
    jass.SetUnitScale(self.handle, current_scale, current_scale, current_scale )
    japi2.SetUnitPressUIHeight(self.handle, self.unit_overhead * current_scale )
end

--获取缩放
function mt:get_size()
    if not self.scale then
        self.scale = self:get_slk('modelScale', 1.0)
    end
    return self.scale
end

--获取真实缩放
function mt:get_current_scale()
    local percentage = math.max(self:get("单位体型"), 0)
    if percentage < 100 then 
        percentage = (100 / (100 + percentage) ) 
    else 
        percentage = percentage * 0.01
    end
    return self:get_size() * percentage
end 

--获取选择缩放
function mt:get_select_scale()
    if not self.select_scale then
        self.select_scale = self:get_slk('scale', 1.0)
    end
    return self.select_scale
end

-- 发布命令
-- @ order  命令
-- @ target 目标
-- @ return 布尔
function mt:issue_order(order, target)
    local bool = false
    local byid = type(order) == 'number'
    if not target then
        if byid then
            bool = jass.IssueImmediateOrderById(self.handle, order)
        else
            bool = jass.IssueImmediateOrder(self.handle, order)
        end
    elseif not target.handle then
        local x, y = target:get()
        if byid then
            bool = jass.IssuePointOrderById(self.handle, order, x, y)
        else
            bool = jass.IssuePointOrder(self.handle, order, x, y)
        end
    else
        if byid then
            bool = jass.IssueTargetOrderById(self.handle, order, target.handle)
        else
            bool = jass.IssueTargetOrder(self.handle, order, target.handle)
        end
    end
    return bool
end

-- 发布给与物品命令
function mt:drop_item_target(item, target)
    if item and target and item.owner == self and item:is_alive() and not item.removed and target:is_alive() and not target:is_hidden() and not target:is_loaded() then 
        jass.UnitDropItemTarget(self.handle, item.handle, target.handle)
    end 
end 
    

--设置单位颜色
function mt:set_color(color)
    self.red, self.green, self.blue, self.alpha = colorlib.rgba(color)
    jass.SetUnitVertexColor(
        self.handle,
        self.red,
        self.green,
        self.blue,
        self.alpha
    )
end

--获取单位颜色
function mt:get_color()
    return colorlib.hex(self.red, self.green, self.blue, self.alpha)
end

--设置单位透明度
function mt:set_alpha(alpha)
    self.alpha = math.min(alpha or self.alpha, 255)
    jass.SetUnitVertexColor(
        self.handle,
        self.red,
        self.green,
        self.blue,
        self.alpha
    )
end

--获取单位透明度
function mt:get_alpha()
    return self.alpha
end

-- 获取单位背包栏最大容量
function mt:get_inventory_size()
    return jass.UnitInventorySize(self.handle)
end

-- 获取单位持有物品数量
function mt:get_inventory_count()
    return self.inventory_count
end

-- 获取单位背包剩余容量
function mt:get_inventory_stock()
    return self:get_inventory_size() - self:get_inventory_count()
end

--增加物品栏数量
function mt:add_inventory_size(value)
    self:set_inventory_size(self:get_inventory_size() + value)
end

--设置物品栏数量
function mt:set_inventory_size(inventory_max)
    self.inventory_max = inventory_max
    if inventory_max == 0 then
        if self:has_ability 'Awpl' then
            self:set_ability_level('Awpl', 7)
            self:remove_ability 'Awpl'
            return
        end
    elseif not self:has_ability 'Awpl' then
        self:add_ability 'Awpl'
        self:set_ability_level('Awpl', 7)
    end
    self:set_ability_level('Awpl', 7 - math.max((math.min(inventory_max, 6)), 1))
end

unit.moving_types = {
    ['none']    = true,     -- 没有
    ['foot']    = true,     -- 步行
    ['horse']   = true,     -- 骑马
    ['fly']     = true,     -- 飞行
    ['hover']   = true,     -- 浮空
    ['float']   = true,     -- 漂浮
    ['amph']    = true,     -- 两栖
    ['unbuild'] = true,     -- 不知道是什么东西
}

--获取单位图标
function mt:get_art()
    if not self.art then
        self.art = self:get_slk("Art", "")
    end
    return self.art
end

--获取单位原本移动类型
function mt:get_base_move_type()
    local result = self:get_slk('movetp')
    if result == '' then
        result = 'none'
    end
    return result
end

--获取单位移动类型
function mt:get_move_type()
    if not self.move_type then
        self.move_type = self:get_base_move_type()
    end
    return self.move_type
end

--设置单位移动类型
function mt:set_move_type(name)
    if name and unit.moving_types[name] then
        self.move_type = name
        japi.SetUnitMoveType(self.handle, name)
    end
end

--召唤单位
function mt:summon_unit(name, where, time)
    local point = where:find_summon_point()
    local summon = self:get_owner():create_unit(name, point)
    if not summon then
        return
    end
    local buff = summon:add_buff("召唤物") {
        source = self,
        point = point,
        time = time,
    }
    return summon, buff
end

--- 派发全局事件(有返回值)
--- @param name string
--- @param ... any
--- @return function
function mt:dispatch(name, ...)
    local ok, res = ac.dispatch(self, name, ...)
    if ok ~= nil then
        return ok, res
    end
    return ac.dispatch(ac.game, name, ...)
end

--- 派发全局事件
--- @param name string
--- @param ... any
--- @return function
function mt:notify(name, ...)
    ac.notify(self, name, ...)
    ac.notify(ac.game, name, ...)
end

--- 注册全局事件
--- @param name string
--- @return function
function mt:event(name)
    return ac.register(self, name)
end

--- 拓展接口名
mt.on = mt.event
mt.register = mt.event
mt.wait = ac.uwait
mt.loop = ac.uloop
mt.timer = ac.utimer

--- 单位拥有技能
function mt:has_ability(id)
    return jass.GetUnitAbilityLevel(self.handle, FourCC(id)) > 0
end

--- 单位添加技能
function mt:add_ability(id)
    -- jass.SetPlayerAbilityAvailable(self:get_owner().handle, FourCC(id), false)
    jass.UnitAddAbility(self.handle, FourCC(id))
    jass.UnitMakeAbilityPermanent(self.handle, FourCC(id), true)
    -- jass.SetPlayerAbilityAvailable(self:get_owner().handle, FourCC(id), true)
end

--- 单位删除技能
function mt:remove_ability(id)
    jass.UnitRemoveAbility(self.handle, FourCC(id))
end

--- 设置技能等级
function mt:set_ability_level(id, level)
    jass.SetUnitAbilityLevel(self.handle, FourCC(id), level)
end

--- 获取护甲类型
function mt:get_amor_type(flag)
    local res = japi.GetUnitState(self.handle, 0x50)
    if flag then
        return res
    end
    return unit.AmorTypes[res]
end

--- 设置护甲类型
function mt:set_amor_type(name)
    japi.SetUnitState(self.handle, 0x50, unit.AmorTypes[name])
end

--- 获取攻击类型
function mt:get_attack_type(flag)
    local res = japi.GetUnitState(self.handle, 0x23)
    if flag then
        return res
    end
    return unit.AttackTypes[res]
end

--- 设置攻击类型
function mt:set_attack_type(name)
    japi.SetUnitState(self.handle, 0x23, unit.AttackTypes[name])
end

--设置转向速度
function mt:set_turn_speed(value)
    jass.SetUnitTurnSpeed(self.handle, value)
end 

--获取转向速度
function mt:get_turn_speed()
    return jass.GetUnitTurnSpeed(self.handle)
end 

--获取默认转向速度
function mt:get_default_turn_speed()
    return jass.GetUnitDefaultTurnSpeed(self.handle)
end 

--获取单位的选取半径
function mt:get_selected_radius()
    return self:get_collision() + 32
end

--是否在指定位置附近(计算碰撞)
function mt:in_range(where, radius)
    return self:get_point() * where:get_point() - self:get_selected_radius() <= radius
end

--是否可选取
function mt:is_can_selector()
    if self.removed then 
        return false 
    end 
    return japi2.GetUnitAsTargetType(self.handle) ~= 0
end 

--- 初始化单位
function mt:init()
    self.buffs           = {}
    self.items           = {}
    self.skills          = {}
    self.sells           = {}
    self.movers          = {}
    self.effects         = {}
    self.attributes      = {}
    self.attackers       = {}
    self.spellbooks      = {}
    self.types           = {}
    self.clothes         = {} -- 存放饰品

    -- 禁用的命令
    self.ignore_orders   = {}

    -- 格子处理

    self.inventory_count = 0

    if self:has_ability 'AInv' then
        self:remove_ability 'AInv'
        self:add_ability 'Awpl'
        self:set_inventory_size(6)
    else
        if self.inventory_size then
            self:add_ability 'Awpl'
            self:set_inventory_size(self.inventory_size)
        end
    end

    -- 同步技能
    self:add_ability 'Sync'

    -- 飞行技能
    self:add_ability 'Arav'
    self:remove_ability 'Arav'

    -- 攻击方式
    self.weapon_type = japi.GetUnitState(self.handle, 0x58)
    self.ward_flag = self:get_slk("type", ""):find("ward")

    japi.SetUnitState(self.handle, 0x53, 0)
    japi.SetUnitState(self.handle, 0x54, 0)


    self:set_model(self.model or self:get_model())
    self:set_size(self.scale or self:get_size())
    if not self:has_ability 'Abld' then
        unit.init_data(self)
    end

    self:notify('单位-初始化', self)

    return self
end

-- 单位变身
function mt:transformat(name)
    if not self:is_alive() then
        self.wait_to_transform_name = name
        return
    end

    if self:get_id() == name then
        return
    end

    local current = ac.lni('unit', self:get_id())
    local session = ac.lni('unit', name)

    if not current then
        log.error("没有找到变身前的单位数据", self:get_id())
        return
    end

    if not session then
        log.error("没有找到变身后的单位数据", name)
        return
    end

    local unitid = symbols[name]
    if not unitid then
        log.error("尝试变身为一个不存在的单位", name)
        return
    end
    
    self:notify("单位-准备变身", self)

    local life_percentage = self:get('当前生命百分比')
    local mana_percentage = self:get('当前魔法百分比')

    local height = self:get_height()

    -- 多出来的格子数量
    local inventory_size = self:get_inventory_size() - (current.inventory_size or 0)

    -- 先丢物品
    -- for item in self:search_items() do
    --     item:notify("on_lose")
    -- end 
    
    -- 移除非永久技能
    for skill in self:each_skill() do
        if not skill.permanent then
            skill:remove()
        end
    end

    local need_change_state = current.state and session.state

    if need_change_state then
        for _,da in ipairs(ac.attribute) do
            local key = da.key
            self:add(key, -1 * (current.state[key] or 0))
        end
    end
    
    japi.DzSetUnitID(self.handle, unitid)

    self:notify("单位-变身开始", self)

    -- 攻击方式
    self.weapon_type = japi.GetUnitState(self.handle, 0x58)

    self:add_ability 'Arav'
    self:remove_ability 'Arav'

    --动画混合时间
    jass.SetUnitBlendTime(self.handle, self:get_slk('blend', 0))
    
    self:set_height(height)

    self.model = nil
    self.scale = nil 
    self._name = name
    self._id = unitid

    if session.name then
        self:set_name(session.name)
    end

    if self:is_hero() and session.proper_name then
        self:set_proper_name(session.proper_name)
    end

    self:set_model(session.model or self:get_model())
    self:set_size(session.scale or self:get_size())

    japi.SetUnitState(self.handle, 0x53, 0)
    japi.SetUnitState(self.handle, 0x54, 0)
    japi.SetUnitMissileModel(self.handle, self:get_slk('Missileart','.mdx') )
    japi.SetUnitState(self.handle, 0x16, self:get("攻击距离"))
    
    self:set_height( self:get_default_height() )
    
    -- 恢复特效
    for effect in self:search_effects() do
        local handle = effect.handle
        if effect._effect_type == 1 then
            effect:unbind()
            effect:bind(self, effect.socket)
        else
            jass.DestroyEffect(handle)
            dbg.handle_unref(handle)
            effect.handle = jass.AddSpecialEffectTarget(effect.model, self.handle, effect.socket)
            dbg.handle_ref(effect.handle)
        end
    end


    if need_change_state then
        for _,da in ipairs(ac.attribute) do
            local key = da.key
            self:add(key, (session.state[key] or 0))
        end
        self:add('攻击间隔', 0)
    end

    -- 在给物品
    -- for item in self:search_items() do
    --     item:notify("on_get")
    -- end 
    
    -- 恢复技能
    for skill in self:each_skill() do
        if skill.has_ability and skill._id and not self:has_ability(skill._id) then
            self:add_ability(skill._id)
            skill:set_cooling(skill:get_cooling(), true)
        end
    end

    -- 添加新单位的技能
    if session.skilllist then
        local info = string.split(session.skilllist, ',')
        if #info[1] ~= 0 then
            for i = 1, #info do
                if not self:find_skill(info[i]) then
                    self:add_skill(info[i])
                end
            end
        end
    end

    if session.inventory_size then
        self:set_inventory_size(inventory_size + session.inventory_size)
    end

    self.default_as_targettype = japi2.GetUnitAsTargetType(self.handle)

    self:ref_restriction("抗性")
    self:ref_restriction("懒惰")
    self:ref_restriction("相位")
    self:ref_restriction("不可选取")
    self:ref_restriction("定身")

    self:set('生命',self:get('生命上限') * life_percentage)
    self:set('魔法',self:get('魔法上限') * mana_percentage)

    self:notify("单位-变身", self)
end

--- 传送
function mt:transfer(pnt, jcm, slu) 
    local owner = self:get_owner() 
    self:notify("单位-打断位移", self, true)
    self:notify("单位-破网而出", self)
    self:notify("单位-即将传送", self)
    self:set_point( pnt , true)
    self:remove_movers()
    if jcm then 
        owner:set_camera( pnt, 0.3)
    end 
    if slu then 
        owner:select( self )
    end 
end

--复活英雄
function mt:revive(where, doEyecandy)
    if not self:is_alive() and self:is_hero() then
        where = where or ac.point(0, 0)
        local x, y = where:get()
        local res = jass.ReviveHero(self.handle, x, y, doEyecandy or false)
        if res == false then
            log.error('错误，复活失败', self, where)
        end
        if self.wait_to_transform_name then
            local name = self.wait_to_transform_name
            self.wait_to_transform_name = nil
            self:transformat(name)
        end
        self:set('生命',self:get('生命上限'))
        self:set('魔法',self:get('魔法上限'))
        self:notify("英雄-复活", self)
    end
end

-- 设置进入战斗状态
function mt:set_fight_active()
    self._unfight_span = 5
    if not self.fight_active then
        self.fight_active = true
        self:notify('单位-进入战斗状态', self)
        table.insert(unit.wait_to_unfight_table, self)
    end
end

-- 设置离开战斗状态
function mt:set_fight_passive()
    if self.fight_active then
        self.fight_active = false
        self:notify('单位-脱离战斗状态', self)
    end
end

-- 单位是否处于战斗状态
function mt:is_fight_active()
    return self.fight_active == true
end

-- 获取单位战斗状态倒计时
function mt:get_fight_active_time()
    if self:is_fight_active() then 
        return self._unfight_span or 0
    end 
    return 0
end

function mt:stop()
	ac.wait(0,function ()
		self:issue_order('stop')
	end)
end

-- 显示视野给指定玩家
function mt:shard_vision(player, flag)
    if self.removed then return end
    local id = player:id()
    local index = self:get_data(("shard_vision[%d]"):format(id)) or 0
    index = index + (flag and 1 or -1)
    self:set_data(("shard_vision[%d]"):format(id), index)
    if flag == true and index == 1 then 
        self:add_restriction "破隐"
        jass.UnitShareVision(self.handle, player.handle, true)
    elseif flag == false and index == 0 then
        self:remove_restriction "破隐"
        jass.UnitShareVision(self.handle, player.handle, false)
    end
end

--更新数据
function mt:update(regen)
    local life_recover = (regen[1] +  self:get('生命上限')*regen[3]*0.01) * unit.regenframe
    local mana_recover = regen[2] * unit.regenframe
    if life_recover ~= 0 and self:is_alive() then
        self:add('生命',life_recover)
    end
    if mana_recover ~= 0 then
        self:add('魔法',mana_recover)
    end
end

-- 刷新回血和回蓝
function mt:refresh_regen()
    if self:has_restriction "禁疗" then 
        unit.regengroup[self] = nil
        return 
	end 
    local life_recover = math_floor(self:get("生命恢复") * 100) * 0.01
    local mana_recover = math_floor(self:get("魔法恢复") * 100) * 0.01
    if life_recover ~= 0 or mana_recover ~= 0 then 
        unit.regengroup[self] = {life_recover, mana_recover,self:get('生命百分比恢复')}
    else 
        unit.regengroup[self] = nil
    end 
end 

--- 杀死单位
function mt:kill(killer, damage)
    if self.removed then
        return false
    end
    if self:is_dead() then
        return false
    end
    
    if damage and self:has_restriction '免死' then
        self:set('生命',1)
        return false
    end

    if not killer then
        killer = self
    end

    if self:dispatch('单位-即将死亡', self, killer, damage) == false then
        self:set('生命',1)
        return false
    end

    self:set('生命',0)

    for bff in self:search_buffs() do
        if bff.keep ~= true then
            bff:remove()
        end
    end

    self:remove_movers()

    if self:dispatch('单位-死亡掉落物品', self, killer, damage) ~= false and not self:is_hero() then
        self:remove_items()
    end
    
    if self:is_alive() then
        jass.KillUnit(self.handle)
        killer:notify('单位-击杀', killer, self, damage)
        self:notify('单位-死亡', self, killer, damage)
    end

    self:remove_effects()
    
    if not self:is_hero() then
        self:wait_to_remove()
        self:remove_skills()
    end

    return true
end

--- 等待删除
function mt:wait_to_remove()
    self._remove_span = 10
    table.insert(unit.wait_to_remove_table, self)
end

--- 删除单位
function mt:remove()
    if self.removed then return end
    if self.be_remove then return end

    self.be_remove = true
    self:notify('单位-即将移除', self)

    self.removed = true
    self._last_point = self:get_point()

    self:remove_items( true )
    self:remove_attackers()
    self:remove_sells()
    self:remove_skills()
    self:remove_movers()
    
    self:remove_buffs()
    self:remove_effects()

    --移除计时器
    if self._timers then
        for i, t in ipairs(self._timers) do
            t:remove()
        end
        self._timers = nil
    end

    --移除触发器
    if self._events then
        for name, event in pairs(self._events) do
            for i, trg in ipairs(event) do
                trg:remove()
                event[i] = nil
            end
            event:remove()
        end
        self.event = nil
    end

    japi.SetUnitPressUIVisible(self.handle, true)
    self:hide()

    if self._creation then
        unit.globals[self._creation] = nil
    end

    unit.regengroup[self] = nil

    local handle = self.handle
    ac.ignore_flag = true
    jass.RemoveUnit(handle)
    dbg.handle_unref(handle)
    jass.SetUnitUserData(handle, -1)
    unit.removeds[handle] = true
    unit.allunits[handle] = nil

    ac.ignore_flag = false

    unit.dbgcount = unit.dbgcount - 1

    return true
end

--- handle检查
--- @params handle
--- @return boolean 是否是可以用的handle
function unit.handle_check(handle)
    if not handle or handle == 0 then 
        return false 
    end 
    if jass.GetUnitTypeId(handle) == 0 then
        return false
    end
    -- 已经移除的单位
    if unit.removeds[handle] then
        return false
    end
    if jass.GetUnitUserData(handle) < 0 then
        return false
    end
    return true
end

--- 获取单位对象 (可以异步使用,不会自动转换)
--- @params handle
function unit:__call(handle)
    if unit.handle_check(handle) then
        return unit.allunits[handle]
    end
end

--- 输出
function unit:__tostring()
    return ("单位[%d]%s"):format(self.handle or 0,self.name)
end

--- 替换找回错误的handle
function unit.replace_handle(newhandle)
    local oldhandle = jass.GetUnitUserData(newhandle)
    local u = unit.allunits[oldhandle]
    if not u then
        log.error('handle 发生错误', oldhandle, newhandle)
        return
    end
    if oldhandle ~= newhandle then
        unit.removeds[oldhandle] = true
        unit.allunits[oldhandle] = nil
        dbg.handle_unref(oldhandle)

        unit.removeds[newhandle] = nil
        unit.allunits[newhandle] = u

        u.handle = newhandle
        dbg.handle_ref(newhandle)

        u.gchash = newhandle
        dbg.gchash(u, newhandle)

        jass.SetUnitUserData(newhandle, newhandle)
        log.info('handle 发生变化', newhandle, oldhandle)
    end
    return u
end

--- 获取单位对象 (不可以异步使用)
--- @params handle
function unit.j_unit(handle)
    --- 先判定是否可用
    if unit.handle_check(handle) then
        local u = unit.allunits[handle]
        if not u then
            -- 检查handle是否变化
            local oldhandle = jass.GetUnitUserData(handle)
            if oldhandle > 0 and oldhandle ~= handle then
                u = unit.replace_handle(handle)
            else
                u = unit.convert_handle(handle)
            end
        end
        return u
    end
end

local GetRealSelectUnit = japi.GetRealSelectUnit 
--- 获取本地单位
function unit.localunit()
    return unit.allunits[GetRealSelectUnit()]
end

--- 转换handle
--- @params handle
function unit.convert_handle(handle)
    --- 转换过程判定单位是否是脚本创建的
    if not ac.ignore_flag then
        log.error('没有被脚本控制的单位', FourCC(jass.GetUnitTypeId(handle)))
        return
    end
    --- 获得对象
    local u = unit.init_handle(handle)
    local unitid = jass.GetUnitTypeId(handle)
    local name = symbols[unitid] or FourCC(unitid)

    local data = ac.lni('unit', name)
    if data then
        if not getmetatable(data) then
            setmetatable(data, unit)
            data.__index = data
            data.__tostring = unit.__tostring
        end
        setmetatable(u, data)
    end

    u._id = unitid
    u._name = name
    u._last_point = u:get_point()


    u:init()

    return u
end

--- 根据handle生成单位对象
--- @params handle
function unit.init_handle(handle)
    local u = setmetatable({}, unit)

    --- 将handle 跟 对象绑定
    u.handle = handle

    --- 加入全局单位表
    unit.allunits[handle] = u
    --- 移除掉handle删除记录
    unit.removeds[handle] = nil

    jass.SetUnitUserData(handle, handle)

    --- 设置gchash值 防止异步
    u.gchash = handle
    dbg.gchash(u, handle)

    --- 句柄引用
    dbg.handle_ref(handle)

    --- 绑定所有者
    u.owner = ac.player(jass.GetOwningPlayer(handle))
    u.name = u:get_name()

    unit.dbgcount = unit.dbgcount + 1

    return u
end



--晚加的属性
local second_state = {
	['基础力量'] = true,
	['基础敏捷'] = true,
	['基础智力'] = true,
	['额外力量'] = true,
	['额外敏捷'] = true,
	['额外智力'] = true,
}
--- 初始化数据
function unit.init_data(u)
    
    if not u:has_ability "Abld" then
        u:set('生命',u:get('生命上限'))
        u:set('魔法',u:get('魔法上限'))
    end

    local name = u:get_id()

    local session = ac.lni("unit", name)
    if session then
        u.name =    session.name or u.name
        u:set_type(session.types)
        if session.restriction then
            for _,name in ipairs(session.restriction) do
                u:add_restriction(name)
            end
        end
        
        local primary = u:get_slk('Primary')
        if primary then 
            if primary == 'INT' then
                u.main_attribute = '智力'
            elseif primary == 'STR' then
                u.main_attribute = '力量'
            elseif primary == 'AGI' then
                u.main_attribute = '敏捷'
            end
        end

        if session.state then
            for k, v in sortpairs(session.state) do
                if second_state[k] == nil then 
                    u:set(k, v)
                end
            end

            for k, v in pairs(second_state) do 
                local v = session.state[k]
                if v then 
                    u:set(k, v)
                end 
            end 

        end

        --技能表
        if session.skill then
            for a=1,12 do
                local name = session.skill[a]
                if name and name~='~' then
                    u:add_skill(name, '英雄', a)
                end
            end
        end
        if session.hide_skill then
            for _,name in ipairs(session.hide_skill) do
                u:add_skill(name, '隐藏')
            end
        end

        --商品出售
        if session.selllist then
            u:add_sells(session.selllist)
        end


    end

    if u.name then
        u:set_name(u.name)
    end

    u:notify('单位-加载数据', u)

    return true
end

--- 创建单位
--- @params owner player 玩家对象
--- @params name string 单位ID
--- @params where point 点
--- @params facing number 面向角度
--- @return unit
function unit.create(owner, name, where, facing)
    local where = where:get_point()
    local x = where and where.x or 0
    local y = where and where.y or 0

    ac.ignore_flag = true

    local unitid = symbols[name] or FourCC(name)
    if not unitid then
        log.error('创建未定义的单位', name)
        return
    end

    local handle = jass.CreateUnit(owner.handle, unitid, x, y, facing or 0)
    --- 创建失败
    if handle == 0 then
        ac.ignore_flag = false
        log.error('创建单位失败', name, unitid,FourCC(unitid))
        return
    end

    -- jass.SetUnitPosition(handle, x, y)

    --- 获得单位对象
    local u = unit.init_handle(handle)
    ac.ignore_flag = false

    local name = symbols[name] and name or u:get_name()
    local data = ac.lni('unit', name)

    if data then
        if not getmetatable(data) then
            setmetatable(data, unit)
            data.__index = data
            data.__tostring = unit.__tostring
        end
        setmetatable(u, data)
    end

    u._id = unitid
    u._name = name
    u._last_point = where or u:get_point()

    -- 触发创建的建筑不需要 这个判定
    u:remove_ability 'Abld'

    --- 初始化单位
    u:init()

    u:notify('单位-创建', u)
    return u
end

-- 给玩家创建单位
function ac.player.__index:create_unit(name, where, facing)
    return unit.create(self, name, where, facing)
end

function mt:create_unit(name, where, facing)
    return self.owner:create_unit(name, where, facing)
end

ac.game:on "单位-获得状态" (function (_, u, b)
    local s = b.source
    if b.debuff and s ~= u then 
        s:set_fight_active()
        u:set_fight_active()
    end 
end)

ac.game:on "单位-攻击" (function(_, u, t)
    u:set_fight_active()
    t:set_fight_active()
end)

ac.game:on "单位-造成伤害" (function(_, u, t)
    if u ~= t then 
        u:set_fight_active()
        t:set_fight_active()
    end 
end)

ac.game:on "单位-受到伤害" (function(_, u, s)
    if u ~= s then 
        u:set_fight_active()
        s:set_fight_active()
    end
end)

ac.message.sync:on "客户端-打断硬直" (function(_, player, u)
    if u:has_restriction "硬直" then
        if u:dispatch('单位-发布打断硬直命令', u) == true then
            -- u:issue_order("stop")
        end
    end
end)

ac.message.sync:on "客户端-打断隐身" (function(_, player, u)
    if u:has_restriction "隐身" then
        if u:dispatch('单位-发布打断隐身命令', u) == true then
            -- u:issue_order("stop")
        end
    end
end)
    

ac.message:on "本地命令" (function(t, name, unithandle, order, flags, ...)
    local u = ac.unit(unithandle)
    if u then
        if (u:has_restriction "硬直") then
            if (order == 'stop' or order == 'smart' or order == 'attack' or order == '使用第1格物品' or order == '使用第2格物品' or order == '使用第3格物品' or order == '使用第4格物品' or order == '使用第5格物品' or order == '使用第6格物品') then
                ac.message.sync("客户端-打断硬直", 0, 0, ac.message.convert_flag("瞬发|独立|交互"))
            end
        end
        if u:dispatch("单位-本地命令", u, name, order, flags, ...) == false then
            return false
        end
        if u:has_restriction "失控" then
            return false
        end
    end
end)

ac.message:on "丢弃物品" (function(t, unithandle, order, flags, itemhandle, widget, x, y)
    local u = ac.unit(unithandle)
    if u then 
        if u:dispatch("单位-本地丢弃物品", u, flags, itemhandle, widget, x, y) == false then
            return false
        end
        if u:has_restriction "失控" then
            return false
        end
        if (u:has_restriction "隐身") then
            ac.message.sync("客户端-打断隐身", 0, 0, ac.message.convert_flag("瞬发|独立|交互"))
        end
    end 
end)

ac.event.register("任意单位-被攻击", function()
    local u = unit.j_unit(jass.GetAttacker())
    local t = unit.j_unit(jass.GetTriggerUnit())
    if u and t then
        if u.attacker then
            u.attacker:notify("attack", t)
        end
        u:notify('单位-攻击', u, t)
        t:notify('单位-被攻击', t, u)
        u:set_fight_active()
        t:set_fight_active()
    end
end)

ac.event.register("任意单位-开始建造", function()
    local handle = jass.GetTriggerUnit()
    ac.ignore_flag = true
    unit.removeds[handle] = nil
    local u = unit.j_unit(handle)
    ac.ignore_flag = false
    if not u then return end
    if u:has_ability "Abld" then
        u:set_amor_type '普通' 
    end
    u:notify('单位-开始建造', u)
end)

ac.event.register("任意单位-取消建造", function()
    local u = unit.j_unit(jass.GetCancelledStructure())
    if not u then return end
    u:notify('单位-取消建造', u)
    u:remove()
end)

ac.event.register("任意单位-建造完成", function()
    local u = unit.j_unit(jass.GetConstructedStructure())
    if not u then return end
    if u:has_ability "Abld" then
        u:set_amor_type '城墙' 
        unit.init_data(u)
        u:remove_ability 'Abld'
    end
    u:notify('单位-建造完成', u)
end)

ac.event.register("任意单位-训练完成", function()
    ac.ignore_flag = true
    local handle = jass.GetTrainedUnit()
    unit.removeds[handle] = nil
    local u = unit.j_unit(handle)
    ac.ignore_flag = false
    if not u then return end
    u:notify('单位-训练完成', u)
end)

ac.event.register("任意单位-升级开始", function()
    local u = ac.unit.j_unit(jass.GetTriggerUnit())
    if not u then return end
    u._upgrading_on = true
    u._upgrading_lp = u:get_life_percentage()
    u._upgrading_mp = u:get_mana_percentage()
end)

ac.event.register("任意单位-取消升级", function()
    local u = ac.unit.j_unit(jass.GetTriggerUnit())
    if not u then return end
    u._upgrading_on = nil
    u._upgrading_lp = nil
    u._upgrading_mp = nil
end)

ac.event.register("任意单位-升级完成", function()
    local u = ac.unit.j_unit(jass.GetTriggerUnit())
    if not u then return end
    if u._upgrading_on == true then
        u:set('生命',u:get('生命上限') * u._upgrading_lp)
        u:set('魔法',u:get('魔法上限') * u._upgrading_mp)
        u._upgrading_on = nil
        u._upgrading_lp = nil
        u._upgrading_mp = nil
        local id = jass.GetUnitTypeId(u.handle)
        local name = symbols[id]
        if name then
            u:transformat(name)
        end
        u:notify("单位-升级完成", u)
    end
end)

ac.event.register("任意单位-发布无目标命令", function()
    if ac.ignore_flag then return end
    local u = ac.unit(jass.GetTriggerUnit())
    if not u then return end
    local id = jass.GetIssuedOrderId()
    u:notify('单位-发布命令', u, id)
end)

ac.event.register("任意单位-发布点目标命令", function()
    if ac.ignore_flag then return end
    local u = ac.unit(jass.GetTriggerUnit())
    if not u then return end
    local x = jass.GetOrderPointX()
    local y = jass.GetOrderPointY()
    local point = ac.point(x, y)
    local id = jass.GetIssuedOrderId()
    u:notify('单位-发布命令', u, id, point)
end)

ac.event.register("任意单位-发布指定目标命令", function()
    if ac.ignore_flag then return end
    local u = ac.unit(jass.GetTriggerUnit())
    if not u then return end
    local handle = jass.GetOrderTarget()
    local target = ac.unit(handle)
    target = target or ac.item.j_item(handle)
    target = target or ac.destructable.j_destructable(handle)
    local id = jass.GetIssuedOrderId()
    if target then
        u:notify('单位-发布命令', u, id, target)
    end
end)

ac.game:on '游戏-生成预设单位' (function(_,not_need)

    if not unit.CreateAllUnits then 

        --unit.CreateAllUnits = code.CreateAllUnits
        unit.CreateAllUnits = code.CreateAllUnits or code.CreateUnits

        code.CreateUnits = function()

        end 
        
        local CreateUnit = jass.CreateUnit 

        code.GlobalUnit = function(id, unitid, x, y, angle, creation)
            local handle = CreateUnit(id, unitid, x, y, angle)
            if handle and handle ~= 0 then 
                unit.removeds[handle] = nil
                local object = unit.j_unit(handle)
                object._creation = creation
                unit.globals[creation] = object
            end 
            return handle
        end 
        
        hook.CreateUnit = function(id, unitid, x, y, angle)
            if not_need then
                return 0
            end
            local handle = CreateUnit(id, unitid, x, y, angle)
            if handle and handle ~= 0 then 
                unit.removeds[handle] = nil
                local u = unit.j_unit(handle)
                if u then
                    u:notify('单位-预设创建',u)
                end
            end 
            return handle
        end 
    end 
    
    
    if unit.CreateAllUnits then 
        ac.ignore_flag = true
        unit.CreateAllUnits()
        ac.ignore_flag = false
    end 
end)

ac.event.register("任意单位-被装载", function()
    local loaded = ac.unit.j_unit(jass.GetLoadedUnit())
    local transport = ac.unit.j_unit(jass.GetTransportUnit()) --运输机
    if not loaded or not transport then return end
    transport:notify('单位-装载单位', transport, loaded)
    loaded:notify('单位-被装载', loaded, transport)
    -- 傻逼装载 装载完了之后相位效果失效
    if loaded:has_restriction "相位" then
        if loaded.loaded_timer then loaded.loaded_timer:remove() end
        loaded.loaded_timer = loaded:loop(0.01, function(timer)
            if not loaded:is_loaded() then
                loaded:ref_restriction("相位")
                timer:remove()
            end
        end)
    end
    -- 删除引导buff
    for bf in loaded:search_buffs() do
        if bf:is_channel() then
            bf:remove()
        end
    end
end)


--- 模块初始化
function unit.init()
    unit.wait_to_remove_table = {}
    unit.wait_to_unfight_table = {}

    ac.loop(unit.regenframe * 1000, function ()
        for u, data in pairs(unit.regengroup) do
            u:update(data)
        end
    end)
    ac.loop(1000, function()
        for i = #unit.wait_to_remove_table, 1, -1 do
            local u = unit.wait_to_remove_table[i]
            u._remove_span = u._remove_span - 1
            if u._remove_span <= 0 then
                table.remove(unit.wait_to_remove_table, i)
                u:remove()
            end
        end
        for i = #unit.wait_to_unfight_table, 1, -1 do
            local u = unit.wait_to_unfight_table[i]
            u._unfight_span = u._unfight_span - 1
            if u._unfight_span <= 0 then
                table.remove(unit.wait_to_unfight_table, i)
                u:set_fight_passive()
            end
        end
    end)
	-- 创建一个 dummy，用于使用马甲技能
	ac.dummy = ac.player[16]:create_unit('dummy', ac.point(0, 0), 0)
end

return unit
